package MVC;

// TODO : Debugger l'envoi de fichiers pour éviter d'envoyer systématiquement 60 GO de données
// TODO : Ajouter une barre de progression dans le transfert de fichier
// TODO : Ajouter des fonctions marrantes
import java.io.IOException;
import protocol.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import javax.swing.DefaultListModel;

public class ChatController {

    private Send mon_send;
    private Receive mon_rcv;
    private ChatModel mon_model;
    private ChatGui mon_gui;
    private DefaultListModel dlm;
    private FileWindow mon_fw;
    private ReceiveTCP mon_rcvTCP;
    private SendTCP mon_sendTCP;

    public void connexion(String username) throws UnknownHostException {

        // Création de l'adresse de broadcast
        Integer mon_int = new Integer(255);
        byte mon_byte = mon_int.byteValue();
        byte[] broadcast = {mon_byte, mon_byte, mon_byte, mon_byte};
        InetAddress adr_broad = InetAddress.getByAddress(broadcast);

        // Création du hello
        Hello hello = new Hello(true, username, InetAddress.getLocalHost());

        //on met l'username dans le modele
        mon_model = new ChatModel(username);
        mon_gui.setModel(mon_model);
        System.out.println(mon_model.getMon_username());

        // Création de l'interface d'envoi de messages
        mon_send = new Send();
        mon_send.init();
        // Création de l'interface d'envoi de fichiers
        mon_sendTCP = new SendTCP();
        mon_sendTCP.setGui(mon_gui);
        // Création de l'interface de réception de messages
        mon_rcv = new Receive(this);
        //on lance la reception
        mon_rcv.setconnecte(true);
        mon_rcv.start();
        // Remarque : l'interface de réception de fichier est crée lorsqu'on en a besoin. Elle utilise un thread donc on l'appelle juste quand il faut


        try {
            mon_send.sendMessage(hello, adr_broad);
        } catch (UnknownHostException ex) {
            System.out.println("Echec de l'envoi du send !");
        }
    }

    public void deconnexion(String username) throws UnknownHostException {

        // Création de l'adresse de broadcast
        Integer mon_int = new Integer(255);
        byte mon_byte = mon_int.byteValue();
        byte[] broadcast = {mon_byte, mon_byte, mon_byte, mon_byte};
        InetAddress adr_broad = InetAddress.getByName("255.255.255.255");

        // Création du bye
        Bye bye = new Bye(username, InetAddress.getLocalHost());

        try {
            mon_send.sendMessage(bye, adr_broad);
            mon_rcv.setconnecte(false);
            dlm.clear();
        } catch (UnknownHostException ex) {
            System.out.println("Echec de l'envoi du send !");
        }
    }

    public void traitement_reception(Message message, InetAddress adr) throws UnknownHostException, InterruptedException, IOException {

        // Traitement différent en fonction de l'objet reçu
        // Si c'est un Hello
        if (message instanceof Hello) {
            Hello m = (Hello) message;
            if (m.getUsername().compareTo(mon_model.getMon_username()) != 0 && !(dlm.contains(m.getUsername()))) {
                // On ajoute le username du gars dans notre dlm
                dlm.addElement(m.getUsername());
                //ajouter la personne dans la liste
                mon_model.add_user(m.getUsername(), adr);
                if (m.isRepreq()) {
                    try {
                        // On répond au gars avec un autre hello
                        Hello hello2 = new Hello(false, mon_model.getMon_username(), InetAddress.getLocalHost());
                        mon_send.sendMessage(hello2, adr);
                    } catch (UnknownHostException ex) {
                        System.out.println("echec de reponse au hello !!!");
                    }
                }
            }
        } // Si c'est un Bye
        else if (message instanceof Bye) {
            // Mettre a jour la liste des utilisateurs
            Bye m = (Bye) message;
            if (m.getUsername().compareTo(mon_model.getMon_username()) != 0) {
                mon_model.delete_user(m.getUsername());
                dlm.removeElement(m.getUsername());
            }

        } // Si c'est un FileNotify
        else if (message instanceof FileNotify) {
            // On informe l'utilisateur
            FileNotify m = (FileNotify) message;
            // Création d'une fenetre de validation ("oui" ou "non")
            mon_fw = new FileWindow(m);
            mon_fw.setController(this);
            mon_fw.setModel(mon_model);
            mon_fw.setVisible(true);

            while (mon_fw.getAck() == 0) {
                //on fait dormir tant que l'utilisateur n'a pas accepté ou refusé
                Thread.sleep(300);
            }

            // Si l'utilisateur local a accepté le transfert de fichier
            if (mon_fw.getAck() == 1) {
                // On envoie une réponse positive au mec distant
                AckFile rep = new AckFile(mon_model.getMon_username(), InetAddress.getLocalHost(), true);
                send(m.getUsername(), rep);
                // Création d'un objet temporaire de type ReceiveTCP pour recevoir le fichier
                mon_rcvTCP = new ReceiveTCP(this, m.getNomFichier());
                // Lancement du thread associé à cet objet
                // (On a besoin d'un nouveau thread pour pouvoir recevoir le fichier et continuer à parler en même temps)
                mon_rcvTCP.start();
                // Remarque : ce thread va s'arrêter tout seul dès que le transfert du fichier sera terminé

                // Si l'utilisateur local a refusé le transfert de fichier
            } else {
                // On envoie une réponse négative au mec distant
                AckFile rep = new AckFile(mon_model.getMon_username(), InetAddress.getLocalHost(), false);
                send(m.getUsername(), rep);
            }

        } //si c'est un AckFile
        else if (message instanceof AckFile) {
            AckFile m = (AckFile) message;
            // Si l'utilisateur distant a accepté le transfert de fichier
            if (m.isAck()) {
                // On avertit l'utilisateur local en lui affichant un prompt
                BasicPrompt mon_prompt = new BasicPrompt("L'utilisateur distant a accepté le transfert de fichier !");
                mon_prompt.setVisible(true);
                // On lui envoie le fichier
                mon_sendTCP.sendFile(mon_sendTCP.getlastfilesent(), adr);
                System.out.println("Transfert du fichier terminé !");

            } // Si l'utilisateur distant a refusé le transfert de fichier
            else {
                // On avertit l'utilisateur local en lui affichant un prompt
                BasicPrompt mon_prompt = new BasicPrompt("L'utilisateur distant a refusé le transfert de fichier !");
                mon_prompt.setVisible(true);
            }
        } else {
            // Si c'est un message de données (ChatMessage), on l'affiche
            ChatMessage m = (ChatMessage) message;
            System.out.println(m.toString() + m);
            Date ma_date = new Date();
            mon_gui.setZoneTexte("["+ma_date+"] : " + m.getUsername() + " : " + m.getMessage() + "\n");
        }
    }

    public void setFileSentInformation(String filename, String filepath) {
        mon_sendTCP.setlastfilepath(filepath);
        mon_sendTCP.setlastfilesent(filename);
    }

    protected void send(String username, Message message) {

        ListElement destinataire = mon_model.getUser(username);

        if (destinataire != null) {
            try {
                mon_send.sendMessage(message, destinataire.getAddr());

                // Si on envoie un ChatMessage, alors on le rend joli en mettant une flèche et le pseudo du gars à qui on l'envoie
                if (message instanceof ChatMessage) {
                    ChatMessage m1 = (ChatMessage) message;
                    Date ma_date = new Date();
                    mon_gui.setZoneTexte("["+ma_date+"] : " + mon_model.getMon_username() + "->" + username + " : " + m1.getMessage() + "\n");
                }

            } catch (UnknownHostException ex) {
                System.out.println("Probleme lors de l'envoi du message !");
            }
        }
    }

    public void setGui(ChatGui g) {
        this.mon_gui = g;
    }

    public ChatModel getModel() {
        return mon_model;
    }

    public DefaultListModel getdlm() {
        return this.dlm;
    }

    protected void createDlm() {
        this.dlm = new DefaultListModel();
    }
}
